/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.explorer.view;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Component;
import java.awt.Graphics;
import java.beans.BeanInfo;
import java.util.*;
import java.lang.ref.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.ImageIcon;
import javax.swing.JTree;
import javax.swing.JList;
import javax.swing.UIManager;
import javax.swing.tree.*;
import javax.swing.ListCellRenderer;
import javax.swing.JLabel;
import org.openide.awt.ListPane;
import org.openide.nodes.Node;
/** Default renderer for nodes. Can be paint either Nodes directly or
* can be used to paint object produces by NodeTreeModel, etc.
*
* @author Jaroslav Tulach
*/
public class NodeRenderer extends Object
implements TreeCellRenderer, ListCellRenderer {
/** shared instance */
private static NodeRenderer sharedInstance;
/** big icons */
private boolean bigIcons;
/** Getter for one shared instance.
*/
public static NodeRenderer sharedInstance () {
if (sharedInstance == null) {
sharedInstance = new NodeRenderer ();
}
return sharedInstance;
}
/** Creates default renderer.
*/
public NodeRenderer () {
}
/** Creates renderer.
* @param bigIcons use big icons if possible?
*/
public NodeRenderer (boolean bigIcons) {
this.bigIcons = bigIcons;
}
//
// Rendering methods
//
/** Finds the component that is capable of drawing the cell in a tree.
* @param value value can be either Node or a value produced by models (like
* NodeTreeModel, etc.)
* @return component to draw the value
*/
public Component getTreeCellRendererComponent(
JTree tree, Object value,
boolean sel, boolean expanded,
boolean leaf, int row, boolean hasFocus
) {
// accepting either Node or Visualizers
VisualizerNode vis = (value instanceof Node) ?
VisualizerNode.getVisualizer (null, (Node)value)
:
(VisualizerNode)value;
return vis.getTree ().getTreeCellRendererComponent (
tree, value, sel, expanded, leaf, row, hasFocus
);
}
/* This is the only method defined by ListCellRenderer. We just
* reconfigure the Jlabel each time we're called.
*/
public java.awt.Component getListCellRendererComponent (
JList list,
Object value, // value to display
int index, // cell index
boolean isSelected, // is the cell selected
boolean cellHasFocus // the list and the cell have the focus
) {
// accepting either Node or Visualizers
VisualizerNode vis = (value instanceof Node) ?
VisualizerNode.getVisualizer (null, (Node)value)
:
(VisualizerNode)value;
if (vis == null) {
vis = VisualizerNode.EMPTY;
}
ListCellRenderer r = bigIcons ?
(ListCellRenderer)vis.getPane () :
(ListCellRenderer)vis.getList ();
return r.getListCellRendererComponent (
list, vis, index, isSelected, cellHasFocus
);
}
// ********************
// Support for dragging
// ********************
/** Value of the cell with "drag under" visual feedback */ // NOI18N
private static VisualizerNode draggedOver;
/** DnD operation enters. Update look and feel to the
* "drag under" state.
* @param value the value of cell which should have
* "drag under" visual feedback
*/
static void dragEnter (Object dragged) {
draggedOver = (VisualizerNode)dragged;
}
/** DnD operation exits. Revert to the normal look and feel. */
static void dragExit () {
draggedOver = null;
}
// ********************
// Cache for ImageIcons
// ********************
/** default icon to use when none is present */
private static final String DEFAULT_ICON = "/org/openide/resources/defaultNode.gif"; // NOI18N
/** loaded default icon */
private static ImageIcon defaultIcon;
/** of icons used (Image, IconImage)*/
private static final WeakHashMap map = new WeakHashMap ();
/** Loades default icon if not loaded.
*/
static ImageIcon getDefaultIcon () {
if (defaultIcon == null) {
defaultIcon = new ImageIcon (DEFAULT_ICON);
}
return defaultIcon;
}
/** Finds imager for given resource.
* @param image image to get
* @return icon for the image
*/
static ImageIcon getIcon (Image image) {
Reference ref = (Reference)map.get (image);
ImageIcon icon = ref == null ? null : (ImageIcon)ref.get ();
if (icon != null) {
return icon;
}
icon = new ImageIcon (image);
map.put (image, new WeakReference (icon));
return icon;
}
//
// Renderers
//
final static class Tree extends DefaultTreeCellRenderer {
/** generated Serialized Version UID */
static final long serialVersionUID = -183570483117501696L;
// Attributes
/** The borders for visual feedback during DnD operation.
* Borders are initialized only when DnD operation becomes active */
static Border activeBorder;
static Border emptyBorder;
private static Component oldRenderer = null;
private boolean displaysOpenedIcon = false;
private boolean nbHasFocus;
private boolean nbDrawsFocusBorderAroundIcon;
{
Object value = UIManager.get("Tree.drawsFocusBorderAroundIcon"); // NOI18N
nbDrawsFocusBorderAroundIcon = (value != null && ((Boolean)value).
booleanValue());
}
/** @return Rendered cell component */
public Component getTreeCellRendererComponent(
JTree tree, Object value,
boolean sel, boolean expanded,
boolean leaf, int row, boolean hasFocus
) {
// accepts only VisualizerNode
VisualizerNode vis = (VisualizerNode)value;
if (expanded != displaysOpenedIcon) {
displaysOpenedIcon = expanded;
update (vis);
}
// provide "drag under" feedback if DnD operation is active // NOI18N
if ((draggedOver != null) && vis == draggedOver)
setBorder(getActiveBorder());
else if (emptyBorder != null)
setBorder(emptyBorder);
setEnabled(tree.isEnabled());
selected = sel;
if(sel)
setForeground(getTextSelectionColor());
else
setForeground(getTextNonSelectionColor());
nbHasFocus = hasFocus;
if ( oldRenderer != null && oldRenderer.getParent() != null ) {
oldRenderer.getParent().remove( oldRenderer );
}
oldRenderer = this;
return this;
}
public void update (VisualizerNode vis) {
if (displaysOpenedIcon) {
setIcon(NodeRenderer.getIcon(vis.node.getOpenedIcon(BeanInfo.ICON_COLOR_16x16)));
} else {
setIcon(NodeRenderer.getIcon(vis.node.getIcon(BeanInfo.ICON_COLOR_16x16)));
}
String displayName = vis.displayName;
String tooltip = vis.shortDescription;
setText(displayName);
if ((tooltip != null) && !tooltip.equals(displayName)) {
setToolTipText(tooltip);
}
else {
setToolTipText(null);
}
}
/** Safe getter for active border. Initializes empty border too */
Border getActiveBorder () {
if (activeBorder == null) {
activeBorder =
new LineBorder(UIManager.getColor("List.focusCellHighlight")); // NOI18N
emptyBorder = new EmptyBorder(1, 1, 1, 1);
}
return activeBorder;
}
/**
* Paints the value. The background is filled based on selected.
*/
public void paint(Graphics g) {
// [IAN]
// this piece of code is incredibly ugly, because it is not possible to set the private
// hasFocus field of DefaultTreeCellRenderer. This code relies on the DefaultTreeCellRenderer's
// paint method not painting the rectangle around the cell when it is not focused.
// If there will be any problems with painting in next versions of swing, this place is a good
// candidate for checking
super.paint(g);
if (nbHasFocus) {
int imageOffset = -1;
if (nbDrawsFocusBorderAroundIcon) {
imageOffset = 0;
}
else if (imageOffset == -1) {
imageOffset = getLabelStart();
}
g.setColor(getBorderSelectionColor());
g.drawRect(imageOffset, 0, getWidth() - 1 - imageOffset,
getHeight() - 1);
}
}
private int getLabelStart() {
javax.swing.Icon currentI = super.getIcon();
if(currentI != null && getText() != null) {
return currentI.getIconWidth() + Math.max(0, getIconTextGap() - 1);
}
return 0;
}
}
/** Implements a
* <code>ListCellRenderer</code> for rendering items of a <code>List</code> containing <code>Node</code>s.
* It displays the node's 16x16 icon and its display name.
*
* @author Ian Formanek
*/
static final class List extends JLabel implements ListCellRenderer {
/** generated Serialized Version UID */
static final long serialVersionUID = -8387317362588264203L;
protected static Border hasFocusBorder;
protected static Border noFocusBorder;
static {
hasFocusBorder = new LineBorder(UIManager.getColor("List.focusCellHighlight")); // NOI18N
noFocusBorder = new EmptyBorder(1, 1, 1, 1);
}
/* This is the only method defined by ListCellRenderer. We just
* reconfigure the Jlabel each time we're called.
*/
public java.awt.Component getListCellRendererComponent (
JList list,
Object value, // value to display
int index, // cell index
boolean isSelected, // is the cell selected
boolean cellHasFocus) // the list and the cell have the focus
{
VisualizerNode vis = (VisualizerNode)value;
if (isSelected) {
setBackground(UIManager.getColor("List.selectionBackground")); // NOI18N
setForeground(UIManager.getColor("List.selectionForeground")); // NOI18N
}
else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
int delta = NodeListModel.findVisualizerDepth (list.getModel (), vis);
Border b = (cellHasFocus || value == draggedOver) ? hasFocusBorder : noFocusBorder;
if (delta > 0) {
javax.swing.Icon icon = this.getIcon ();
b = new javax.swing.border.CompoundBorder (
new EmptyBorder (0, icon.getIconWidth () * delta, 0, 0), b
);
}
setBorder(b);
return this;
}
public void update (VisualizerNode vis) {
setOpaque(true);
setBorder(noFocusBorder);
setIcon(NodeRenderer.getIcon(vis.node.getIcon(java.beans.BeanInfo.ICON_COLOR_16x16)));
setText(vis.displayName);
}
}
/** Icon renderer
*/
final static class Pane extends JLabel implements ListCellRenderer {
/** generated Serialized Version UID */
static final long serialVersionUID = -5100925551665387243L;
protected static Border hasFocusBorder;
protected static Border noFocusBorder;
static {
hasFocusBorder = new LineBorder(java.awt.Color.black);
noFocusBorder = new EmptyBorder(1, 1, 1, 1);
}
/** Creates a new NetbeansListCellRenderer */
public Pane () {
setOpaque(true);
setBorder(noFocusBorder);
setVerticalTextPosition(JLabel.BOTTOM);
setHorizontalAlignment(JLabel.CENTER);
setHorizontalTextPosition(JLabel.CENTER);
}
/** This is the only method defined by ListCellRenderer. We just
* reconfigure the Jlabel each time we're called.
* @param list The ListPane.
* @param value The value returned by list.getModel().getElementAt(index).
* @param index The cells index.
* @param isSelected True if the specified cell was selected.
* @param cellHasFocus True if the specified cell has the focus.
* @return A component whose paint() method will render the specified value.
*/
public Component getListCellRendererComponent (
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus
) {
if (isSelected){
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setBorder(cellHasFocus ? hasFocusBorder : noFocusBorder);
return this;
}
public void update (VisualizerNode vis) {
ImageIcon icon = NodeRenderer.getIcon(vis.node.getIcon(BeanInfo.ICON_COLOR_32x32));
setIcon(icon);
setText(vis.displayName);
}
}
}
/*
* Log
* 6 Gandalf 1.5 1/13/00 Ian Formanek NOI18N
* 5 Gandalf 1.4 1/12/00 Ian Formanek NOI18N
* 4 Gandalf 1.3 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 3 Gandalf 1.2 9/22/99 Petr Hrebejk Caching of Renderers in
* CellRendererPane disabled
* 2 Gandalf 1.1 8/27/99 Jaroslav Tulach List model can display
* more levels at once.
* 1 Gandalf 1.0 8/27/99 Jaroslav Tulach
* $
*/